package com.harisucici.websocketlib.im;

import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;

import com.harisucici.websocketlib.utils.Constants;
import com.harisucici.websocketlib.utils.Utils;

import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Protocol;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;


public class HWebSocketOKManager {
    private final static String TAG = "HWebSocketOKManager";
    private final static int CLOSE_CODE = 1001;
    private final static int T_CODE = 1002;
    private static HWebSocketOKManager mInstance = null;
    private static HWebSocketOKManager hWebSocketOKManager;
    private Map<String, String> map;
    private OkHttpClient client;
    private Request request;
    private IReceiveMessage receiveMessage;
    private WebSocket mWebSocket;
    private boolean isConnect = false;
    private int connectNum = 0;
    //心跳包发送时间计时
    private long sendTime = 0L;
    // 发送心跳包
    private Handler mHandler;
    private String url;
    private long heart;

    //    public static HWebSocketOKManager getInstance() {
//        if (null == mInstance) {
//            synchronized (HWebSocketOKManager.class) {
//                if (mInstance == null) {
//                    mInstance = new HWebSocketOKManager();
//                }
//            }
//        }
//        return mInstance;
//    }


    public static synchronized HWebSocketOKManager getInstance() {
        if (hWebSocketOKManager == null) {
            hWebSocketOKManager = new HWebSocketOKManager();
        }
        return hWebSocketOKManager;
    }

    /**
     * 设置url,心跳
     */
    public void initHWebSocketService(IReceiveMessage message, String url, long heart) {
        this.url = url;
        this.heart = heart;
        onInit(message);
    }

    /**
     * 关闭连接
     */
    public void onClose() {
        if (isConnect()) {
            mWebSocket.cancel();
            mWebSocket.close(CLOSE_CODE, "客户端主动关闭连接");
        }

        if (mHandler != null) {
            mHandler.removeCallbacksAndMessages(null);
            mHandler = null;
        }
        onRelease();
    }

    /**
     * 发送消息,字符串
     */
    public boolean send(String text) {
        if (!isConnect()) {
            return false;
        }
        return mWebSocket.send(text);
    }

    /**
     * 发送消息,字符集
     */
    public boolean send(ByteString byteString) {
        if (!isConnect()) {
            return false;
        }
        return mWebSocket.send(byteString);
    }


    private void onInit(IReceiveMessage message) {
        mHandler = new Handler();
        client = new OkHttpClient.Builder()
                .writeTimeout(Constants.WriteTimeout, TimeUnit.SECONDS)
                .readTimeout(Constants.ReadTimeout, TimeUnit.SECONDS)
                .connectTimeout(Constants.ConnectTimeout, TimeUnit.SECONDS)
                .build();
        request = new Request.Builder().url(url).build();
        receiveMessage = message;
        onConnect();
    }

    // 连接
    private void onConnect() {
        if (isConnect()) {
            Log.i(TAG, "连接成功");
            return;
        }
        //连接 打开心跳
        client.newWebSocket(request, createListener());
    }

    // 重连
    private void onReconnect() {
        if (connectNum <= Constants.MAX_NUM) {
            try {
                Thread.sleep(Constants.MILLIS);
                onConnect();
                connectNum++;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } else {
            Log.i(TAG, "最大重连" + Constants.MAX_NUM + "次,请检查url");
        }
    }

    // 释放单例及其所引用的资源
    private void onRelease() {
        try {
            if (mInstance != null) {
                mInstance = null;
            }
        } catch (Exception e) {
            Log.e(TAG, "release : " + e.toString());
        }
    }

    // 判断是否连接
    private boolean isConnect() {
        return mWebSocket != null && isConnect;
    }


    // 发送心跳包
    private Runnable heartBeatRunnable = new Runnable() {
        @Override
        public void run() {
            if (System.currentTimeMillis() - sendTime >= heart) {
                sendTime = System.currentTimeMillis();
                boolean isSend = send("心跳内容");
                Log.i(TAG, "心跳是否发送成功" + isSend);
            }
            //每隔一定的时间，对长连接进行一次心跳检测
            mHandler.postDelayed(this, heart);
        }
    };

    private WebSocketListener createListener() {
        return new WebSocketListener() {
            @Override
            public void onOpen(WebSocket webSocket, Response response) {
                super.onOpen(webSocket, response);
                Log.i(TAG, "WebSocket.onOpen," + response.toString());
                mWebSocket = webSocket;
                isConnect = response.code() == 101;
                if (!isConnect) {
                    onReconnect();
                } else {
                    Log.i(TAG, "WebSocket连接成功");
                    if (receiveMessage != null) {
                        receiveMessage.onConnectSuccess(response.code(), response.message());
                    }
                    mHandler.postDelayed(heartBeatRunnable, heart);
                }
            }

            @Override
            public void onMessage(WebSocket webSocket, String text) {
                super.onMessage(webSocket, text);
                if (receiveMessage != null) {
                    Log.i(TAG, text);
                    map = Utils.getInstance().jso2map(text);
                    if (map == null) {
                        return;
                    }
                    int code = Integer.parseInt(map.get("code"));
                    // 收到的消息：{"cmdType":"P2P","code":1000,"msg":"不支持的消息类型"}
                    if (code == Constants.WEB_CODE_OK) {
                        receiveMessage.onMessage(map.get("cmdType"), map.get("payLoad"));
                    } else {
                        //错误信息
                        receiveMessage.onError(code, map.get("type"), map.get("msg"));
                    }
                }
            }

            @Override
            public void onClosing(WebSocket webSocket, int code, String reason) {
                super.onClosing(webSocket, code, reason);
                Log.i(TAG, "WebSocket.onClosing," + reason);
                mWebSocket = null;
                isConnect = false;
                if (mHandler != null) {
                    mHandler.removeCallbacksAndMessages(null);
                }
                if (receiveMessage != null) {
                    receiveMessage.onClosing(code, reason);
                }
            }

            @Override
            public void onClosed(WebSocket webSocket, int code, String reason) {
                super.onClosed(webSocket, code, reason);
                mWebSocket = null;
                isConnect = false;
                if (mHandler != null) {
                    mHandler.removeCallbacksAndMessages(null);
                }
                if (receiveMessage != null) {
                    receiveMessage.onClosed(code, reason);
                }
            }

            @Override
            public void onFailure(WebSocket webSocket, Throwable t, Response response) {
                super.onFailure(webSocket, t, response);
                if (response != null) {
                    Log.i(TAG, "WebSocket.onFailure" + response.message());
                } else {
                    response=new Response.Builder().request(request).protocol(Protocol.HTTP_1_1).code(T_CODE).message(t.getMessage()).build();
                }
//                Log.i(TAG, "WebSocket.onFailure.reason" + t.getMessage());
                isConnect = false;
                if (mHandler != null) {
                    mHandler.removeCallbacksAndMessages(null);
                }
                if (receiveMessage != null) {
                    receiveMessage.onConnectFailed(response.code(), response.message());

                }
                if (!TextUtils.isEmpty(t.getMessage()) && !t.getMessage().equals("Socket closed")) {
                    onReconnect();
                }

            }
        };
    }


    // 接收信息接口
    public interface IReceiveMessage {
        void onConnectSuccess(int code, String msg);

        void onConnectFailed(int code, String msg);

        void onClosing(int code, String msg);

        void onClosed(int code, String msg);

        void onMessage(String type, String msg);

        void onError(int code, String type, String msg);
    }
}